from datetime import datetime
from decimal import Decimal
from unittest import mock

import pytest
from django_countries.fields import Country
from django_scopes import scopes_disabled
from pytz import UTC

from pretix.base.models import (
    InvoiceAddress,
    Order,
    OrderPosition,
    SeatingPlan,
    SubEvent,
)
from pretix.base.models.orders import OrderFee


@pytest.fixture
def variations(item):
    v = []
    v.append(item.variations.create(value='ChildA1', default_price='12.00'))
    v.append(item.variations.create(value='ChildA2', default_price='13.00'))
    return v


@pytest.fixture
def variations2(item2):
    v = []
    v.append(item2.variations.create(value='ChildB1', default_price='12.00'))
    v.append(item2.variations.create(value='ChildB2', default_price='13.00'))
    return v


@pytest.fixture
def order(event, item, taxrule):
    testtime = datetime(2017, 12, 1, 10, 0, 0, tzinfo=UTC)

    with mock.patch('django.utils.timezone.now') as mock_now:
        mock_now.return_value = testtime
        o = Order.objects.create(
            code='FOO',
            event=event,
            email='dummy@dummy.test',
            status=Order.STATUS_PENDING,
            secret='k24fiuwvu8kxz3y1',
            datetime=datetime(2017, 12, 1, 10, 0, 0, tzinfo=UTC),
            expires=datetime(2017, 12, 10, 10, 0, 0, tzinfo=UTC),
            total=23,
            locale='en',
        )
        o.fees.create(
            fee_type=OrderFee.FEE_TYPE_PAYMENT,
            value=Decimal('0.25'),
            tax_rate=Decimal('19.00'),
            tax_value=Decimal('0.05'),
            tax_rule=taxrule,
        )
        InvoiceAddress.objects.create(order=o, company='Sample company', country=Country('NZ'))
        return o


@pytest.fixture
def order_position(item, order, subevent, taxrule, variations):
    op = OrderPosition.objects.create(
        order=order,
        item=item,
        subevent=subevent,
        variation=variations[0],
        tax_rule=taxrule,
        tax_rate=taxrule.rate,
        tax_value=Decimal('3'),
        price=Decimal('23'),
        attendee_name_parts={'full_name': 'Peter'},
        secret='z3fsn8jyufm5kpk768q69gkbyr5f4h6w',
    )
    return op


TEST_SUBEVENT_RES = {
    'active': False,
    'event': 'dummy',
    'presale_start': None,
    'date_to': None,
    'date_admission': None,
    'name': {'en': 'Foobar'},
    'frontpage_text': None,
    'date_from': '2017-12-27T10:00:00Z',
    'presale_end': None,
    'seating_plan': None,
    'seat_category_mapping': {},
    'id': 1,
    'variation_price_overrides': [],
    'location': None,
    'geo_lat': None,
    'geo_lon': None,
    'is_public': True,
    'item_price_overrides': [],
    'meta_data': {'type': 'Workshop'},
}


@pytest.fixture
def item(event):
    return event.items.create(name='Budget Ticket', default_price=23)


@pytest.fixture
def item2(event2):
    return event2.items.create(name='Another Ticket', default_price=23)


@pytest.mark.django_db
def test_subevent_list(token_client, organizer, event, subevent):
    res = dict(TEST_SUBEVENT_RES)
    res['id'] = subevent.pk
    res['last_modified'] = subevent.last_modified.isoformat().replace('+00:00', 'Z')
    resp = token_client.get('/api/v1/organizers/{}/events/{}/subevents/'.format(organizer.slug, event.slug))
    assert resp.status_code == 200
    assert [res] == resp.data['results']
    resp = token_client.get('/api/v1/organizers/{}/subevents/'.format(organizer.slug))
    assert resp.status_code == 200
    assert [res] == resp.data['results']

    resp = token_client.get(
        '/api/v1/organizers/{}/events/{}/subevents/?active=false'.format(organizer.slug, event.slug)
    )
    assert [res] == resp.data['results']
    resp = token_client.get('/api/v1/organizers/{}/events/{}/subevents/?active=true'.format(organizer.slug, event.slug))
    assert [] == resp.data['results']

    resp = token_client.get(
        '/api/v1/organizers/{}/events/{}/subevents/?event__live=false'.format(organizer.slug, event.slug)
    )
    assert [res] == resp.data['results']
    resp = token_client.get(
        '/api/v1/organizers/{}/events/{}/subevents/?event__live=true'.format(organizer.slug, event.slug)
    )
    assert [] == resp.data['results']

    resp = token_client.get(
        '/api/v1/organizers/{}/events/{}/subevents/?ends_after=2017-12-27T09:59:59Z'.format(organizer.slug, event.slug)
    )
    assert [res] == resp.data['results']
    resp = token_client.get(
        '/api/v1/organizers/{}/events/{}/subevents/?ends_after=2017-12-27T10:01:01Z'.format(organizer.slug, event.slug)
    )
    assert [] == resp.data['results']


@pytest.mark.django_db
def test_subevent_list_filter(token_client, organizer, event, subevent):
    resp = token_client.get(
        '/api/v1/organizers/{}/events/{}/subevents/?attr[type]=Workshop'.format(organizer.slug, event.slug)
    )
    assert resp.status_code == 200
    assert resp.data['count'] == 1

    resp = token_client.get(
        '/api/v1/organizers/{}/events/{}/subevents/?attr[type]=Conference'.format(organizer.slug, event.slug)
    )
    assert resp.status_code == 200
    assert resp.data['count'] == 0


@pytest.mark.django_db
def test_subevent_create(team, token_client, organizer, event, subevent, meta_prop, item):
    meta_prop.allowed_values = 'Conference\nWorkshop'
    meta_prop.save()
    team.can_change_organizer_settings = False
    team.save()
    organizer.meta_properties.create(name='protected', protected=True)
    resp = token_client.post(
        '/api/v1/organizers/{}/events/{}/subevents/'.format(organizer.slug, event.slug),
        {
            'name': {'de': 'Demo Subevent 2020 Test', 'en': 'Demo Subevent 2020 Test'},
            'active': False,
            'date_from': '2017-12-27T10:00:00Z',
            'date_to': '2017-12-28T10:00:00Z',
            'date_admission': None,
            'presale_start': None,
            'presale_end': None,
            'location': None,
            'item_price_overrides': [],
            'variation_price_overrides': [],
            'meta_data': {
                'type': 'Workshop',
                'protected': 'ignored',
            },
        },
        format='json',
    )
    assert resp.status_code == 201
    assert not subevent.active
    with scopes_disabled():
        assert subevent.meta_values.filter(property__name=meta_prop.name, value='Workshop').exists()
        assert not subevent.meta_values.filter(
            property__name='ignored',
        ).exists()

    resp = token_client.post(
        '/api/v1/organizers/{}/events/{}/subevents/'.format(organizer.slug, event.slug),
        {
            'name': {'de': 'Demo Subevent 2020 Test', 'en': 'Demo Subevent 2020 Test'},
            'active': False,
            'date_from': '2017-12-27T10:00:00Z',
            'date_to': '2017-12-28T10:00:00Z',
            'date_admission': None,
            'presale_start': None,
            'presale_end': None,
            'location': None,
            'item_price_overrides': [],
            'variation_price_overrides': [],
            'meta_data': {'foo': 'bar'},
        },
        format='json',
    )
    assert resp.status_code == 400
    assert resp.content.decode() == '{"meta_data":["Meta data property \'foo\' does not exist."]}'

    resp = token_client.post(
        '/api/v1/organizers/{}/events/{}/subevents/'.format(organizer.slug, event.slug),
        {
            'name': {'de': 'Demo Subevent 2020 Test', 'en': 'Demo Subevent 2020 Test'},
            'active': False,
            'date_from': '2017-12-27T10:00:00Z',
            'date_to': '2017-12-28T10:00:00Z',
            'date_admission': None,
            'presale_start': None,
            'presale_end': None,
            'location': None,
            'item_price_overrides': [],
            'variation_price_overrides': [],
            'meta_data': {meta_prop.name: 'bar'},
        },
        format='json',
    )
    assert resp.status_code == 400
    assert resp.content.decode() == '{"meta_data":["Meta data property \'type\' does not allow value \'bar\'."]}'

    resp = token_client.post(
        '/api/v1/organizers/{}/events/{}/subevents/'.format(organizer.slug, event.slug),
        {
            'name': {'de': 'Demo Subevent 2020 Test', 'en': 'Demo Subevent 2020 Test'},
            'active': False,
            'date_from': '2017-12-27T10:00:00Z',
            'date_to': '2017-12-28T10:00:00Z',
            'date_admission': None,
            'presale_start': None,
            'presale_end': None,
            'location': None,
            'item_price_overrides': [{'item': item.pk, 'price': '23.42'}],
            'variation_price_overrides': [],
            'meta_data': {'type': 'Workshop'},
        },
        format='json',
    )
    assert resp.status_code == 201
    assert item.default_price == Decimal('23.00')
    with scopes_disabled():
        assert event.subevents.get(id=resp.data['id']).item_price_overrides[item.pk] == Decimal('23.42')

    resp = token_client.post(
        '/api/v1/organizers/{}/events/{}/subevents/'.format(organizer.slug, event.slug),
        {
            'name': {'de': 'Demo Subevent 2020 Test', 'en': 'Demo Subevent 2020 Test'},
            'active': False,
            'date_from': '2017-12-27T10:00:00Z',
            'date_to': '2017-12-28T10:00:00Z',
            'date_admission': None,
            'presale_start': None,
            'presale_end': None,
            'location': None,
            'item_price_overrides': [{'item': 555, 'price': '23.42'}],
            'variation_price_overrides': [],
            'meta_data': {'type': 'Workshop'},
        },
        format='json',
    )
    assert resp.status_code == 400
    assert (
        resp.content.decode() == '{"item_price_overrides":[{"item":["Invalid pk \\"555\\" - object does not exist."]}]}'
    )


@pytest.mark.django_db
def test_subevent_update(
    token_client,
    organizer,
    event,
    subevent,
    item,
    item2,
    meta_prop,
    variations,
    variations2,
):
    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'date_from': '2018-12-27T10:00:00Z',
            'date_to': '2018-12-28T10:00:00Z',
        },
        format='json',
    )
    assert resp.status_code == 200
    with scopes_disabled():
        subevent = event.subevents.get(id=subevent.id)
    assert subevent.date_from == datetime(2018, 12, 27, 10, 0, tzinfo=UTC)
    assert subevent.date_to == datetime(2018, 12, 28, 10, 0, tzinfo=UTC)

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {'date_from': '2017-12-27T10:00:00Z', 'date_to': '2017-12-26T10:00:00Z'},
        format='json',
    )
    assert resp.status_code == 400
    assert resp.content.decode() == '{"non_field_errors":["The event cannot end before it starts."]}'

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'presale_start': '2017-12-27T10:00:00Z',
            'presale_end': '2017-12-26T10:00:00Z',
        },
        format='json',
    )
    assert resp.status_code == 400
    assert resp.content.decode() == '{"non_field_errors":["The event\'s presale cannot end before it starts."]}'

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {'meta_data': {meta_prop.name: 'Conference'}},
        format='json',
    )
    assert resp.status_code == 200
    with scopes_disabled():
        assert (
            organizer.events.get(slug=event.slug)
            .subevents.get(id=resp.data['id'])
            .meta_values.filter(property__name=meta_prop.name, value='Conference')
            .exists()
        )

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {'meta_data': {}},
        format='json',
    )
    assert resp.status_code == 200
    with scopes_disabled():
        assert not subevent.meta_values.filter(property__name=meta_prop.name).exists()

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {'meta_data': {'test': 'test'}},
        format='json',
    )
    assert resp.status_code == 400
    assert resp.content.decode() == '{"meta_data":["Meta data property \'test\' does not exist."]}'

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'item_price_overrides': [{'item': item.pk, 'price': '99.99'}],
        },
        format='json',
    )
    assert resp.status_code == 200
    with scopes_disabled():
        assert subevent.items.get(id=item.pk).default_price == Decimal('23.00')
    assert subevent.item_price_overrides[item.pk] == Decimal('99.99')

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'item_price_overrides': [{'item': item.pk, 'price': '88.88'}],
        },
        format='json',
    )
    assert resp.status_code == 200
    with scopes_disabled():
        assert event.subevents.get(id=subevent.id).item_price_overrides[item.pk] == Decimal('88.88')

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'item_price_overrides': [{'item': item.pk, 'price': None}],
        },
        format='json',
    )
    assert resp.status_code == 200
    with scopes_disabled():
        assert item.pk not in event.subevents.get(id=subevent.id).item_price_overrides

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'item_price_overrides': [{'item': item.pk, 'price': '12.34'}],
        },
        format='json',
    )
    assert resp.status_code == 200
    with scopes_disabled():
        assert event.subevents.get(id=subevent.id).item_price_overrides[item.pk] == Decimal('12.34')

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'item_price_overrides': [],
        },
        format='json',
    )
    assert resp.status_code == 200
    with scopes_disabled():
        assert item.pk not in event.subevents.get(id=subevent.id).item_price_overrides

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'item_price_overrides': [{'item': 123, 'price': '99.99'}],
        },
        format='json',
    )
    assert resp.status_code == 400
    assert (
        resp.content.decode() == '{"item_price_overrides":[{"item":["Invalid pk \\"123\\" - object does not exist."]}]}'
    )

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'item_price_overrides': [{'item': item2.id, 'price': '99.99'}],
        },
        format='json',
    )
    assert resp.status_code == 400
    assert resp.content.decode() == '{"non_field_errors":["One or more items do not belong to this event."]}'

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'variation_price_overrides': [{'variation': variations[0].pk, 'price': '99.99'}],
        },
        format='json',
    )
    assert resp.status_code == 200
    with scopes_disabled():
        assert subevent.variations.get(id=variations[0].pk).default_price == Decimal('12.00')
        assert subevent.var_price_overrides[variations[0].pk] == Decimal('99.99')

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'variation_price_overrides': [{'variation': variations[0].pk, 'price': '88.88'}],
        },
        format='json',
    )
    assert resp.status_code == 200
    with scopes_disabled():
        assert event.subevents.get(id=subevent.id).var_price_overrides[variations[0].pk] == Decimal('88.88')

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'variation_price_overrides': [{'variation': variations[0].pk, 'price': None}],
        },
        format='json',
    )
    assert resp.status_code == 200
    with scopes_disabled():
        assert variations[0].pk not in event.subevents.get(id=subevent.id).var_price_overrides

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'variation_price_overrides': [{'variation': variations[0].pk, 'price': '12.34'}],
        },
        format='json',
    )
    assert resp.status_code == 200
    with scopes_disabled():
        assert event.subevents.get(id=subevent.id).var_price_overrides[variations[0].pk] == Decimal('12.34')

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'variation_price_overrides': [],
        },
        format='json',
    )
    assert resp.status_code == 200
    with scopes_disabled():
        assert variations[0].pk not in event.subevents.get(id=subevent.id).var_price_overrides

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'variation_price_overrides': [{'variation': 123, 'price': '99.99'}],
        },
        format='json',
    )
    assert resp.status_code == 400
    assert (
        resp.content.decode()
        == '{"variation_price_overrides":[{"variation":["Invalid pk \\"123\\" - object does not exist."]}]}'
    )

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'variation_price_overrides': [{'variation': variations2[0].pk, 'price': '99.99'}],
        },
        format='json',
    )
    assert resp.status_code == 400
    assert resp.content.decode() == '{"non_field_errors":["One or more variations do not belong to this event."]}'


@pytest.mark.django_db
def test_subevent_update_keep_subeventitems(token_client, organizer, event, subevent, item, item2):
    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'item_price_overrides': [{'item': item.pk, 'price': '88.88', 'disabled': True}],
        },
        format='json',
    )
    assert resp.status_code == 200
    with scopes_disabled():
        assert event.subevents.get(id=subevent.id).item_overrides[item.pk].disabled

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'date_from': '2017-12-27T10:00:00Z',
        },
        format='json',
    )
    assert resp.status_code == 200
    with scopes_disabled():
        assert event.subevents.get(id=subevent.id).item_overrides[item.pk].disabled


@pytest.mark.django_db
def test_subevent_detail(token_client, organizer, event, subevent):
    res = dict(TEST_SUBEVENT_RES)
    res['id'] = subevent.pk
    res['last_modified'] = subevent.last_modified.isoformat().replace('+00:00', 'Z')
    resp = token_client.get(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk)
    )
    assert resp.status_code == 200
    assert res == resp.data


@pytest.mark.django_db
def test_subevent_delete(token_client, organizer, event, subevent):
    resp = token_client.delete(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk)
    )
    assert resp.status_code == 204
    with scopes_disabled():
        assert not event.subevents.filter(pk=subevent.id).exists()


@pytest.mark.django_db
def test_subevent_with_order_position_not_delete(token_client, organizer, event, subevent, item, order_position):
    resp = token_client.delete(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk)
    )
    assert resp.status_code == 403
    assert (
        resp.content.decode() == '{"detail":"The sub-event can not be deleted as it has already been used in '
        "orders. Please set 'active' to false instead to hide it from users.\"}"
    )
    with scopes_disabled():
        assert event.subevents.filter(pk=subevent.id).exists()


@pytest.fixture
def seatingplan(event, organizer, item):
    return SeatingPlan.objects.create(
        name='Plan',
        organizer=organizer,
        layout="""{
  "name": "Grosser Saal",
  "categories": [
    {
      "name": "Stalls",
      "color": "red"
    }
  ],
  "zones": [
    {
      "name": "Main Area",
      "position": {
        "x": 0,
        "y": 0
      },
      "rows": [
        {
          "row_number": "0",
          "seats": [
            {
              "seat_guid": "0-0",
              "seat_number": "0-0",
              "position": {
                "x": 0,
                "y": 0
              },
              "category": "Stalls"
            },
            {
              "seat_guid": "0-1",
              "seat_number": "0-1",
              "position": {
                "x": 33,
                "y": 0
              },
              "category": "Stalls"
            },
            {
              "seat_guid": "0-2",
              "seat_number": "0-2",
              "position": {
                "x": 66,
                "y": 0
              },
              "category": "Stalls"
            }
          ],
          "position": {
            "x": 0,
            "y": 0
          }
        }
      ]
    }
  ],
  "size": {
    "width": 600,
    "height": 400
  }
}""",
    )


@pytest.mark.django_db
def test_subevent_update_seating(token_client, organizer, event, item, subevent, seatingplan):
    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {'seating_plan': seatingplan.pk, 'seat_category_mapping': {'Stalls': item.pk}},
        format='json',
    )
    assert resp.status_code == 200
    subevent.refresh_from_db()
    assert subevent.seating_plan == seatingplan
    with scopes_disabled():
        assert subevent.seats.count() == 3
        assert subevent.seats.filter(product=item).count() == 3
        m = subevent.seat_category_mappings.get()
    assert m.layout_category == 'Stalls'
    assert m.product == item


@pytest.mark.django_db
def test_subevent_update_seating_invalid_product(token_client, organizer, event, item, seatingplan, subevent):
    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'seating_plan': seatingplan.pk,
            'seat_category_mapping': {'Stalls': item.pk + 2},
        },
        format='json',
    )
    assert resp.status_code == 400
    assert resp.content.decode() == '{"seat_category_mapping":["Item \'%d\' does not exist."]}' % (item.pk + 2)


@pytest.mark.django_db
def test_subevent_update_seating_change_mapping(token_client, organizer, event, item, seatingplan, subevent):
    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {'seating_plan': seatingplan.pk, 'seat_category_mapping': {'Stalls': item.pk}},
        format='json',
    )
    assert resp.status_code == 200
    subevent.refresh_from_db()
    assert subevent.seating_plan == seatingplan
    with scopes_disabled():
        assert subevent.seats.count() == 3
        assert subevent.seats.filter(product=item).count() == 3
        m = subevent.seat_category_mappings.get()
    assert m.layout_category == 'Stalls'
    assert m.product == item

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {
            'seat_category_mapping': {
                'VIP': item.pk,
            }
        },
        format='json',
    )
    assert resp.status_code == 200
    subevent.refresh_from_db()
    assert subevent.seating_plan == seatingplan
    with scopes_disabled():
        assert subevent.seats.count() == 3
        m = subevent.seat_category_mappings.get()
        assert subevent.seats.filter(product=None).count() == 3
    assert m.layout_category == 'VIP'
    assert m.product == item


@pytest.mark.django_db
def test_remove_seating(token_client, organizer, event, item, seatingplan, subevent):
    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {'seating_plan': seatingplan.pk, 'seat_category_mapping': {'Stalls': item.pk}},
        format='json',
    )
    assert resp.status_code == 200
    subevent.refresh_from_db()
    assert subevent.seating_plan == seatingplan
    with scopes_disabled():
        assert subevent.seats.count() == 3
        assert subevent.seat_category_mappings.count() == 1

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {'seating_plan': None},
        format='json',
    )
    assert resp.status_code == 200
    subevent.refresh_from_db()
    assert subevent.seating_plan is None
    with scopes_disabled():
        assert subevent.seats.count() == 0
        assert subevent.seat_category_mappings.count() == 0


@pytest.mark.django_db
def test_remove_seating_forbidden(token_client, organizer, event, item, seatingplan, order_position, subevent):
    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {'seating_plan': seatingplan.pk, 'seat_category_mapping': {'Stalls': item.pk}},
        format='json',
    )
    assert resp.status_code == 200
    subevent.refresh_from_db()
    assert subevent.seating_plan == seatingplan
    with scopes_disabled():
        assert subevent.seats.count() == 3
        assert subevent.seat_category_mappings.count() == 1

        order_position.seat = subevent.seats.first()
        order_position.save()

    resp = token_client.patch(
        '/api/v1/organizers/{}/events/{}/subevents/{}/'.format(organizer.slug, event.slug, subevent.pk),
        {'seating_plan': None},
        format='json',
    )
    assert resp.status_code == 400
    assert (
        resp.content.decode() == '{"seating_plan":["You can not change the plan since seat \\"0-0\\" is not '
        'present in the new plan and is already sold."]}'
    )


@pytest.mark.django_db
def test_subevent_create_with_seating(token_client, organizer, event, subevent, item, seatingplan):
    resp = token_client.post(
        '/api/v1/organizers/{}/events/{}/subevents/'.format(organizer.slug, event.slug),
        {
            'name': {'de': 'Demo Subevent 2020 Test', 'en': 'Demo Subevent 2020 Test'},
            'active': False,
            'date_from': '2017-12-27T10:00:00Z',
            'date_to': '2017-12-28T10:00:00Z',
            'date_admission': None,
            'presale_start': None,
            'presale_end': None,
            'location': None,
            'item_price_overrides': [{'item': item.pk, 'price': '23.42'}],
            'variation_price_overrides': [],
            'seat_category_mapping': {'Stalls': item.pk},
            'meta_data': {},
            'seating_plan': seatingplan.pk,
        },
        format='json',
    )
    assert resp.status_code == 201
    with scopes_disabled():
        subevent = SubEvent.objects.get(pk=resp.data['id'])
        assert subevent.seats.count() == 3
        assert subevent.seat_category_mappings.count() == 1
